package cc.verywell.pureblock.func;

import java.nio.ByteBuffer;
import java.util.Arrays;

import cc.verywell.pureblock.func.node.Node;
import cc.verywell.pureblock.func.node.NodeBucket;
import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.net.Msg;
import cc.verywell.pureblock.net.NormalSession;
import cc.verywell.pureblock.net.Timelog;

/**
* 用于在FuncProviderList之前的握手;
* 
* Copyright 2019 TanYaqiu
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月17日 下午6:32:48
*/
public class FuncProviderInit implements FuncList {

	final private FuncProvider[] sentFuncs;
	final private NodeBucket nodeBucket;
	final private FuncProviderManager funcManager;
	public FuncProviderInit(FuncProvider[] sentFuncs,NodeBucket nodeBucket,FuncProviderManager funcManager) {
		this.sentFuncs = sentFuncs;
		this.nodeBucket=nodeBucket;
		this.funcManager = funcManager;
	}
	@Override
	public boolean hasFunc(FuncProvider provider) {
		return false;
	}

	/**
	 * 解包线程，这里出错会关掉channel;
	 * @param bb
	 * @return
	 */
	@Override
	public Msg decode(ByteBuffer bb, NormalSession nc) {
		//改用tl.getLastReadTime();//long localReceiveTime = System.currentTimeMillis(); //先取得时间，尽量缩短公差;
		Node m = new Node(bb);
		if(m.getSalt()!=nc.salt) {
			throw new UnEqualSaltException("session:"+Integer.toHexString(nc.salt)+" != "+Integer.toHexString(m.getSalt())); 
		}
		Timelog tl = nc.getTimelog();
		long localReceiveTime = tl.getLastReadTime();
		if(localReceiveTime==0)localReceiveTime = System.currentTimeMillis();
		if(tl instanceof FuncTimelog) {
			((FuncTimelog)tl).initTime(m.getRemoteSentTime(), localReceiveTime);
		}
		if(Pblog.DEBUG)Pblog.DEBUG("init remote [pubKey:",m.getPubKey(),"],[func:",Arrays.toString(m.getFuncs()),"],[remote:",Arrays.toString(m.getRemote()),"]");
		
		//这里初始化 以及整理对方node内容;
		NodeBucket.ValueShell vs = nodeBucket.allowNodeConnect(m,nc,localReceiveTime);
		if(vs==null) {
			//这里throw会断开链接;
			throw new DuplicateConnException("not allow pubKey:["+Pblog.byteArray2Hex(m.getPubKey())+"]"  );
			//return m; //不能由toDo处理，因为Node没有继承getFunc()，在context处就开始出错了;
		}else if(vs.getSession()!=nc) {
			throw new DuplicateConnException("already connected at "+vs.getSession());
		}
		
		FuncList f = funcManager.getFuncsInited(vs, m.getFuncs(), sentFuncs);
		nc.setFunc(f);
		f.newSession(nc); //这里出错会关掉channel，这样很好;
		
		nc.annouceInited(); //释放客户端线程;
		return null;
	}
	
	/**
	 * 返回true 会暂停读包, 
	 * 可以通过 NormalSession.startRead()恢复读包;
	 * 留意TimeOut,TimeoutRunner依然会自动断开连接的;
	 * @param Msg msg
	 * @param NormalSession nc
	 * @return true PauseRead;
	 */
	public boolean toDo(Msg msg,NormalSession nc) {
		throw new IllegalAccessError();
//		try {
//			//会执行toDo,就一定是要关闭链接的了;
//			Node m = (Node)msg;
//			if(Pblog.IO)Pblog.printIO("Duplicate Connection [pubKey:",m.getPubKey(),"] at ",nc);
//		}finally {
//			nc.close();
//		}
//		return true;//返回true或false都无所谓;
	}

	

	/**
	 */
	@Override
	public void encode(Msg msg, NormalSession nc, ByteBuffer bb) {
		if(msg instanceof Node) {
			msg.write(bb, nc);
		}else {
			throw new IllegalArgumentException("FuncProviderInit only encode Node.");
		}
	}

//	@Override
//	public String funcName() {
//		return "__FuncProviderInit__";
//	}
	@Override
	public String toString() {
		//用于出错时找原因;
		return this.getClass().getName()+"$"+Integer.toHexString(this.hashCode());
	}
	
	///////////////////////////////////////////////
	
	
	public void newSession(NormalSession nc) {
		throw new IllegalAccessError();
	}
	public void closeSession(NormalSession nc) {}
	
	public void sessionTimeout(NormalSession nc) {}

	public void close(){
		throw new IllegalAccessError();
	}
	@Override
	public NodeBucket.ValueShell getNode() {
		return null; //AioProvider会问;
	}

}
